import * as React from 'react';
import {
  ArrowBackIosNew as ArrowIcon,
  KeyboardArrowLeft as KeyboardArrowLeftIcon,
  KeyboardArrowRight as KeyboardArrowRightIcon,
  MailLock as MailIcon,
  Person as PersonIcon,
  Key as PasswordIcon,
  VisibilityOff as VisibilityOffIcon,
  Visibility as VisibilityOnIcon,
} from '@mui/icons-material';
import {
  Grid,
  Box,
  Typography,
  Container,
  Paper,
  Fab,
  Button,
  TextField,
  MobileStepper,
  FormControlLabel,
  Checkbox,
  Stepper,
  Step,
  StepLabel,
  FormControl,
  FormHelperText, InputAdornment, IconButton,
} from '@mui/material';
import { useEffect, useRef, useState } from 'react';
import { IMaskInput } from 'react-imask';
import { useFormik } from 'formik';
import * as yup from 'yup';
import { getAccountData, updateAccountData } from 'routes/accounts';
import { encrypt } from 'functions/crypto';
import parsePhoneNumber from 'libphonenumber-js';
import { logIn } from 'functions/cookies';
import { styled } from '@mui/material/styles';
import StepConnector, { stepConnectorClasses } from '@mui/material/StepConnector';
import showAlert from 'functions/showAlert';
import { errorMessages as e } from '../../alertMessages';
import { nameRegex, phoneNumberRegex } from '../../constants';

const TextMaskCustom = React.forwardRef((props, ref) => {
  const { onChange, ...other } = props;
  return (
    <IMaskInput
      {...other}
      mask="8 (000) 000-00-00"
      definitions={{
        '#': /[1-9]/,
      }}
      inputRef={ref}
      onAccept={(value) => onChange({ target: { name: props.name, value } })}
      overwrite
    />
  );
});

const CustomTextField = (props) => {
  const {
    id,
    name,
    label,
    autoComplete,
    formik,
    validation,
    isShowPassword,
    handleClickShowPassword,
  } = props;

  return (
    <TextField
      size="small"
      fullWidth
      name={name}
      sx={{ height: '68px', width: '350px' }}
      color={validation ? 'success' : 'primary'}
      label={label}
      type={((name === 'password' && !isShowPassword) || (name === 'confirmed_password' && !isShowPassword)) ? 'password' : 'text'}
      id={id}
      autoComplete={autoComplete}
      value={formik.values[name]}
      onChange={formik.handleChange}
      error={formik.touched[name] && Boolean(formik.errors[name])}
      helperText={formik.touched[name] && formik.errors[name]}
      InputProps={{
        inputComponent: name === 'phone_number' ? TextMaskCustom : undefined,
        endAdornment: (name === 'password' || name === 'confirmed_password') && (
          <InputAdornment position="end">
            <IconButton
              aria-label="toggle password visibility"
              onClick={handleClickShowPassword}
              edge="end"
            >
              {isShowPassword ? <VisibilityOffIcon /> : <VisibilityOnIcon />}
            </IconButton>
          </InputAdornment>
        ),
      }}
    />
  );
};

export default function SignUp({ setIsShowSignIn, setIsShowSignUp }) {
  const [activeStep, setActiveStep] = useState(0);
  const [isValidEmail, setIsValidEmail] = useState(undefined);
  const [isValidPersonalData, setIsValidPersonalData] = useState(undefined);
  const [isValidPassword, setIsValidPassword] = useState(undefined);
  const isEmailChange = useRef(false);
  const isPersonalDataChange = useRef(false);
  const [isShowPassword, setIsShowPassword] = useState(false);
  const [phoneNumber, setPhoneNumber] = useState(undefined);
  const [registerAccountData, setRegisterAccountData] = useState(null);
  const [stateEmail, setStateEmail] = useState(null);
  const emailErrorMessage = useRef('');

  const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
  };

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1);
  };

  const handleClickShowPassword = () => {
    setIsShowPassword(!isShowPassword);
  };

  const initialValuesEmail = {
    email: '',
  };

  const initialValuesPersonalData = {
    last_name: '',
    first_name: '',
    middle_name: '',
    phone_number: '',
    checked: false,
  };

  const initialValuesPassword = {
    password: '',
    confirmed_password: '',
  };

  const validationSchemaEmail = yup.object({
    email: yup
      .string()
      .email(e.ERROR_INVALID_EMAIL)
      .max(255, e.ERROR_MAX_EMAIL)
      .required(e.ERROR_REQ_EMAIL),
  });

  const validationSchemaPersonalData = yup.object({
    last_name: yup
      .string()
      .matches(nameRegex, e.ERROR_INVALID_LAST_NAME)
      .required(e.ERROR_REQ_LAST_NAME),
    first_name: yup
      .string()
      .matches(nameRegex, e.ERROR_INVALID_FIRST_NAME)
      .required(e.ERROR_REQ_FIRST_NAME),
    middle_name: yup
      .string()
      .matches(nameRegex, e.ERROR_INVALID_MIDDLE_NAME)
      .required(e.ERROR_REQ_MIDDLE_NAME),
    phone_number: yup
      .string()
      .min(11, e.ERROR_FULL_PHONE_NUMBER)
      .matches(phoneNumberRegex, e.ERROR_INVALID_PHONE_NUMBER)
      .required(e.ERROR_REQ_PHONE_NUMBER),
    checked: yup
      .bool()
      .oneOf([true], e.ERROR_REQ_CHECKED),
  });

  const validationSchemaPassword = yup.object({
    password: yup
      .string(e.ERROR_REQ_PASSWORD)
      .max(255, e.ERROR_MAX_PASSWORD)
      .min(8, e.ERROR_MIN_PASSWORD)
      .required(e.ERROR_REQ_PASSWORD),
    confirmed_password: yup
      .string(e.ERROR_REQ_PASSWORD_CONFIRM)
      .max(255, e.ERROR_MAX_PASSWORD)
      .min(8, e.ERROR_MIN_PASSWORD)
      .oneOf([yup.ref('password')], e.ERROR_PASSWORDS_DONT_MATCH)
      .required(e.ERROR_REQ_PASSWORD_CONFIRM),
  });

  const handleSubmitCheckEmail = (values, { setErrors }) => {
    if (stateEmail === null || stateEmail !== values.email) {
      setStateEmail(values.email);
      getAccountData({ email: values.email }).then(({ status }) => {
        if (status === 'success') {
          setIsValidEmail(true);
          setRegisterAccountData({ email: values.email });
          emailErrorMessage.current = '';
          isEmailChange.current = false;
          handleNext();
        } else if (status === 'warning') {
          setIsValidEmail(false);
          emailErrorMessage.current = e.ERROR_EMAIL_ALREADY_EXIST;
          setErrors({ email: emailErrorMessage.current });
        } else if (status === 'error') {
          setIsValidEmail(false);
          emailErrorMessage.current = e.ERROR_EMAIL_NOT_FOUND;
          setErrors({ email: emailErrorMessage.current });
        }
      });
    } else if (emailErrorMessage.current !== '') {
      setErrors({ email: emailErrorMessage.current });
    } else if (isValidEmail === true && emailErrorMessage.current === '') {
      if (isEmailChange.current) isEmailChange.current = false;
      handleNext();
    }
  };

  const handleSubmitPersonalData = (values) => {
    if (isValidPersonalData === undefined) {
      const personalData = {
        last_name: values.last_name,
        first_name: values.first_name,
        middle_name: values.middle_name,
        phone_number: phoneNumber,
        email: stateEmail,
      };
      setRegisterAccountData(personalData);
      setIsValidPersonalData(true);
    }
    isPersonalDataChange.current = false;
    handleNext();
  };

  const handleSubmitSignUp = (values) => {
    if (isValidPassword === undefined) {
      setIsValidPassword(true);
      const body = {
        last_name: registerAccountData.last_name,
        first_name: registerAccountData.first_name,
        middle_name: registerAccountData.middle_name,
        password: values.password,
        phone_number: phoneNumber,
        email: registerAccountData.email,
        register_status: true,
      };
      const encryptedBody = encrypt(JSON.stringify(body));
      updateAccountData(encryptedBody)
        .then((response) => {
          if (response) {
            showAlert('success', 'Регистрация успешно завершена');
            logIn(response, false);
          } else {
            showAlert('error', 'Возникла ошибка при регистрации');
            setIsValidPassword(false);
          }
        })
        .catch((error) => showAlert('error', error));
    }
  };

  const formikEmail = useFormik({
    initialValues: initialValuesEmail,
    validationSchema: validationSchemaEmail,
    onSubmit: handleSubmitCheckEmail,
  });

  const formikPersonalData = useFormik({
    initialValues: initialValuesPersonalData,
    validationSchema: validationSchemaPersonalData,
    onSubmit: handleSubmitPersonalData,
  });

  const formikFinishSignUp = useFormik({
    initialValues: initialValuesPassword,
    validationSchema: validationSchemaPassword,
    onSubmit: handleSubmitSignUp,
  });

  const handleClickGoBack = () => {
    setIsShowSignIn(true);
    setIsShowSignUp(false);
  };

  const steps = [
    {
      label: 'Проверка электронной почты',
      code: (
        <form onSubmit={formikEmail.handleSubmit}>
          <CustomTextField
            id="email sign up"
            name="email"
            label="Адрес электронной почты"
            autoComplete="email"
            formik={formikEmail}
            validation={isValidEmail}
            setValidation={setIsValidEmail}
            isChange={isEmailChange}
          />
        </form>
      ),
      icon: (<MailIcon />),
      formik: formikEmail,
      validation: isValidEmail,
    },
    {
      label: 'Ввод данных пользователя',
      code: (
        <form onSubmit={formikPersonalData.handleSubmit}>
          <CustomTextField
            id="last_name"
            name="last_name"
            label="Фамилия"
            autoComplete="last-name"
            formik={formikPersonalData}
            validation={isValidPersonalData}
            setValidation={setIsValidPersonalData}
          />
          <CustomTextField
            id="first_name"
            name="first_name"
            label="Имя"
            autoComplete="first-name"
            formik={formikPersonalData}
            validation={isValidPersonalData}
          />
          <CustomTextField
            id="middle_name"
            name="middle_name"
            label="Отчество"
            autoComplete="middle-name"
            formik={formikPersonalData}
            validation={isValidPersonalData}
          />
          <CustomTextField
            id="phone_number"
            name="phone_number"
            label="Номер телефона"
            autoComplete="phone-number"
            formik={formikPersonalData}
            validation={isValidPersonalData}
          />
          <FormControl
            error={formikPersonalData.touched.checked && Boolean(formikPersonalData.errors.checked)}
            variant="standard"
            sx={{ height: '50px', pb: 0.4, pt: 0.6 }}
          >
            <FormControlLabel
              sx={{ height: '20px' }}
              control={(
                <Checkbox
                  type="checkbox"
                  name="checked"
                  color={isValidPersonalData ? 'success' : 'primary'}
                  disabled={Object.values(formikPersonalData.values).includes('')}
                  onChange={formikPersonalData.handleChange}
                  checked={formikPersonalData.values.checked}
                />
              )}
              label="Данные верны"
            />
            {formikPersonalData.touched.checked && Boolean(formikPersonalData.errors.checked) && (
              <FormHelperText>
                {formikPersonalData.touched.checked && formikPersonalData.errors.checked}
              </FormHelperText>
            )}
          </FormControl>
        </form>
      ),
      icon: (<PersonIcon />),
      formik: formikPersonalData,
      validation: isValidPersonalData,
    },
    {
      label: 'Завершение регистрации',
      code: (
        <form onSubmit={formikFinishSignUp.handleSubmit}>
          <CustomTextField
            id="password"
            name="password"
            label="Пароль"
            autoComplete="new-password"
            formik={formikFinishSignUp}
            isShowPassword={isShowPassword}
            handleClickShowPassword={handleClickShowPassword}
          />
          <CustomTextField
            id="confirmed_password"
            name="confirmed_password"
            label="Подвердите пароль"
            autoComplete="confirmed-new-password"
            formik={formikFinishSignUp}
            isShowPassword={isShowPassword}
            handleClickShowPassword={handleClickShowPassword}
          />
          <Button
            type="submit"
            fullWidth
            size="small"
            variant="contained"
            sx={{ mb: 3 }}
          >
            Зарегистрироваться
          </Button>
        </form>
      ),
      icon: (<PasswordIcon />),
      formik: formikFinishSignUp,
      validation: isValidPassword,
    },
  ];

  useEffect(() => {
    if (isValidEmail !== undefined && Object.values(formikEmail.errors).length === 0) {
      setIsValidEmail(undefined);
    }
    if (isEmailChange.current === false) {
      formikEmail.setTouched({});
      isEmailChange.current = true;
    }
  }, [formikEmail.values, formikEmail.errors]);

  useEffect(() => {
    if (Object.values(formikEmail.errors).length > 0
        && formikEmail.touched.email
        && isValidEmail !== false) {
      setIsValidEmail(false);
    }
  }, [formikEmail.errors, formikEmail.touched]);

  useEffect(() => {
    if (isValidPersonalData !== undefined
        && Object.values(formikPersonalData.errors).length === 0) {
      setIsValidPersonalData(undefined);
    }
    if (isPersonalDataChange.current === false) {
      formikPersonalData.setFieldValue('checked', false);
      formikPersonalData.setTouched({});
      isPersonalDataChange.current = true;
    }
  }, [formikPersonalData.values, formikPersonalData.errors]);

  useEffect(() => {
    if (Object.values(formikPersonalData.errors).length > 0
        && Object.values(formikPersonalData.touched).length > 0
        && isValidPersonalData !== false) {
      setIsValidPersonalData(false);
    }
  }, [formikPersonalData.errors, formikPersonalData.touched]);

  useEffect(() => {
    if (isValidPassword !== undefined
        && Object.values(formikFinishSignUp.errors).length === 0) {
      setIsValidPassword(undefined);
    }
  }, [formikFinishSignUp.values, formikFinishSignUp.errors]);

  useEffect(() => {
    if (Object.values(formikFinishSignUp.errors).length > 0
        && Object.values(formikFinishSignUp.touched).length > 0
        && isValidPassword !== false) {
      setIsValidPassword(false);
    }
  }, [formikFinishSignUp.errors, formikFinishSignUp.touched]);

  useEffect(() => {
    if (Object.values(formikFinishSignUp.errors).length > 0
        && Object.values(formikFinishSignUp.touched).length > 0
        && isValidPassword !== false) {
      setIsValidPassword(false);
    }
  }, [formikFinishSignUp.errors, formikFinishSignUp.touched]);

  useEffect(() => {
    if (formikPersonalData.values.phone_number) {
      const newPhoneNumber = parsePhoneNumber(formikPersonalData.values.phone_number, 'RU');
      if (newPhoneNumber) {
        setPhoneNumber(8 + newPhoneNumber.nationalNumber);
      }
    }
  }, [formikPersonalData.values.phone_number]);

  const AvatarStepIconRoot = styled('div')(({ theme, ownerState }) => ({
    m: 1,
    left: '35%',
    backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[700] : '#ccc',
    zIndex: 1,
    color: '#fff',
    width: 42,
    height: 42,
    display: 'flex',
    borderRadius: '50%',
    justifyContent: 'center',
    alignItems: 'center',

    ...(ownerState.active && ownerState.icon === (activeStep + 1)
        && steps[activeStep]?.validation === undefined && {
      backgroundColor: '#1969d2',
      boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
    }),

    ...(ownerState.active && ownerState.icon === (activeStep + 1)
        && steps[activeStep]?.validation === true && {
      backgroundColor: '#2e7d32',
      boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
    }),

    ...(ownerState.active && ownerState.icon === (activeStep + 1)
        && steps[activeStep]?.validation === false && {
      backgroundColor: '#d32f2f',
      boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
    }),

    ...(ownerState.completed && {
      backgroundColor: '#2e7d32',
    }),

  }));

  const connectorStepColor = () => {
    if (steps[activeStep]?.validation === undefined) {
      return 'linear-gradient(to right, #2e7d32 50%, #1969d2 50%)';
    }
    if (steps[activeStep]?.validation === false) {
      return 'linear-gradient(to right, #2e7d32 50%, #d32f2f 50%)';
    }
    return '';
  };

  const ColorlibConnector = styled(StepConnector)(({ theme }) => ({
    [`&.${stepConnectorClasses.alternativeLabel}`]: {
      top: 20,
    },
    [`&.${stepConnectorClasses.completed}`]: {
      [`& .${stepConnectorClasses.line}`]: {
        backgroundColor: '#2e7d32',
      },
    },
    [`&.${stepConnectorClasses.active}`]: {
      [`& .${stepConnectorClasses.line}`]: {
        backgroundImage: connectorStepColor(),
        backgroundColor: '#2e7d32',
      },
    },
    [`& .${stepConnectorClasses.line}`]: {
      height: 3,
      border: 0,
      backgroundColor:
          theme.palette.mode === 'dark' ? theme.palette.grey[800] : '#eaeaf0',
      borderRadius: 1,
    },
  }));

  function AvatarStepIcon(props) {
    const { active, completed, icon } = props;

    const icons = {
      1: steps[0].icon,
      2: steps[1].icon,
      3: steps[2].icon,
    };

    return (
      <AvatarStepIconRoot ownerState={{ completed, active, icon }}>
        {/* eslint-disable-next-line react/destructuring-assignment */}
        {icons[String(icon)]}
      </AvatarStepIconRoot>
    );
  }

  return (
    <Container component="main" maxWidth="xs">
      <Box sx={{ marginTop: 8, display: 'flex' }}>
        <Paper
          elevation={3}
          sx={{
            alignItems: 'center',
            display: 'flex',
            flexDirection: 'column',
            my: { xs: 3, md: 6 },
            p: { xs: 2, md: 3 },
          }}
        >
          <Grid
            container
            alignItems="center"
            justifyContent="space-between"
          >
            <Grid item>
              <Fab
                size="small"
                sx={{ right: '100%' }}
                onClick={handleClickGoBack}
              >
                <ArrowIcon />
              </Fab>
            </Grid>
            <Grid item xs>
              <Stepper
                sx={{ mr: 2, pr: 2, mb: 1 }}
                activeStep={activeStep}
                alternativeLabel
                connector={<ColorlibConnector />}
              >
                {steps.map((item) => (
                  <Step key={item.label}>
                    <StepLabel StepIconComponent={AvatarStepIcon} />
                  </Step>
                ))}
              </Stepper>
            </Grid>
          </Grid>
          <Typography component="h1" variant="h5" sx={{ mt: 1, mb: 0.5 }}>
            {steps[activeStep]?.label}
          </Typography>
          <Box sx={{ mt: 3, mb: 0 }}>
            {steps[activeStep]?.code}
            <MobileStepper
              sx={{ pb: 0, pt: 0, px: 0 }}
              variant="text"
              steps={steps.length}
              position="static"
              activeStep={activeStep}
              nextButton={activeStep !== 2 ? (
                <form onSubmit={steps[activeStep]?.formik.handleSubmit}>
                  <Button size="small" type="submit">
                    Вперед
                    <KeyboardArrowRightIcon />
                  </Button>
                </form>
              ) : (<Button disabled sx={{ width: '80px' }} />)}
              backButton={activeStep !== 0 ? (
                <Button size="small" onClick={handleBack}>
                  <KeyboardArrowLeftIcon />
                  Назад
                </Button>
              ) : (<Button disabled sx={{ width: '95px' }} />)}
            />
          </Box>
        </Paper>
      </Box>
    </Container>
  );
}
